﻿using LowCoding.Common;
using LowCoding.Common.Security;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
using System.Text;

namespace LowCoding.API
{
    /// <summary>
    /// 日志记录
    /// </summary>
    public class LogFilterAttribute : IAsyncActionFilter
    {
        /// <summary>
        /// 请求日志拦截
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            try
            {
                //============== 这里是执行方法之前获取数据 ====================

                // 获取控制器、路由信息
                var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;

                // 获取请求的方法
                var method = actionDescriptor.MethodInfo;

                // 获取 HttpContext 和 HttpRequest 对象
                var httpContext = context.HttpContext;
                var httpRequest = httpContext.Request;

                // 获取客户端 Ipv4 地址
                //var remoteIPv4 = httpContext.GetRemoteIpAddressToIPv4();

                // 获取请求的 Url 地址
                var requestUrl = httpRequest.GetDisplayUrl();

                // 获取来源 Url 地址
                //var refererUrl = httpRequest.();

                // 获取请求参数（写入日志，需序列化成字符串后存储）
                var parameters = context.ActionArguments;

                // 获取操作人（必须授权访问才有值）"userId" 为你存储的 claims type，jwt 授权对应的是 payload 中存储的键名
                var userId = AppManager.GetCurrentUser()?.UserId;

                // 请求时间
                var requestedTime = DateTimeOffset.Now;

                var sw = new Stopwatch();
                sw.Start();
                //============== 这里是执行方法之后获取数据 ====================
                var actionContext = await next();
                sw.Stop();

                // 判断是否请求成功，没有异常就是请求成功
                var isRequestSucceed = actionContext.Exception == null;

                // 这里写入日志或者写入表中~~~~~~~~~~~~~~~~~~~~
                StringBuilder sb = new StringBuilder();
                sb.Append($"请求方式：{httpRequest.Method}\r\n");
                //sb.Append($"请求客户端地址：{remoteIPv4}\r\n");
                sb.Append($"请求Url地址：{requestUrl}\r\n");
                //sb.Append($"请求来源Url地址：{refererUrl}\r\n");
                sb.Append($"请求参数：{parameters.ToJson()}\r\n");
                sb.Append($"请求用户ID：{userId}\r\n");
                sb.Append($"请求时间：{requestedTime}\r\n");
                sb.Append($"请求耗时：{sw.ElapsedMilliseconds}ms\r\n");
                sb.Append($"请求是否成功：{isRequestSucceed}\r\n");
                LogHelper.WriteLog(sb.ToString());
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorLog(ex);
            }
        }

        /// <summary>
        /// 读取请求参数
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public string GetRequestValues(ResultExecutingContext context)
        {
            // 后续添加了获取请求的请求体，如果在实际项目中不需要删除即可
            long contentLen = context.HttpContext.Request.ContentLength == null ? 0 : context.HttpContext.Request.ContentLength.Value;
            if (contentLen > 0)
            {
                // 读取请求体中所有内容
                System.IO.Stream stream = context.HttpContext.Request.Body;
                if (context.HttpContext.Request.Method == "POST")
                {
                    stream.Position = 0;
                }
                byte[] buffer = new byte[contentLen];
                stream.Read(buffer, 0, buffer.Length);
                // 转化为字符串
                return System.Text.Encoding.UTF8.GetString(buffer);
            }
            return string.Empty;
        }

        /// <summary>
        /// 读取返回数据
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public string GetResponseValues(ResultExecutingContext context)
        {
            var response = context.Result.GetType().Name == "EmptyResult" ? new { Value = "无返回结果" } : context.Result as dynamic;
            return JsonHelper.ToJson(response.Value);
        }

        /// <summary>
        /// 判断是否有 NoLogAttribute
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private static bool SkipNoLog(ActionExecutingContext context)
        {
            var controllerActionDescriptor = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
            return controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(NoLogAttribute), true);
        }

        /// <summary>
        /// 判断是否具有属性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="context"></param>
        /// <returns></returns>
        private static bool CheckAttribute<T>(ActionExecutingContext context)
        {
            var controllerActionDescriptor = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
            return controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(T), true);
        }
    }
}